﻿using Infrastructures;
using IRepository;
using Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConcreteService
{
    public class ProjectService : CommonService
    {
        public IList<Project> ListProjectByRole(APPRole createType, int topNumber)
        {
            IProjectRepository repo = ServiceFactory.CreateInstance<IProjectRepository>();
            return repo.ListProjectByRole(createType, topNumber);
        }

        public ProjectData CreateProjectData(ProjectData obj, string oper)
        {
            if (obj == null || oper == null)
                throw new Exception("ProjectService.UpdateProjectData :: parameter is null");

            IProjectRepository repo = ServiceFactory.CreateInstance<IProjectRepository>();
            obj = repo.CreateProjectData(obj);
            ProcessHelper.ProcessAfterDone(obj, oper, EventType.Create, false);
            return obj;
        }

        public ProjectData UpdateProjectData(ProjectData obj, string oper)
        {
            if (obj == null || oper == null)
                throw new Exception("ProjectService.UpdateProjectData :: parameter is null");

            IProjectRepository repo = ServiceFactory.CreateInstance<IProjectRepository>();
            repo.UpdateProjectData(obj);

            ProcessHelper.ProcessAfterDone(obj, oper, EventType.Update, false);

            return obj;
        }

        public void DeleteProjectData(int id, ProjectDataType type, string oper)
        {
            IProjectRepository repo = ServiceFactory.CreateInstance<IProjectRepository>();

            var data = Get<Project>(id.ToString());
            if (data == null)
                throw new Exception("ProjectService.DeleteProjectData :: parameter is null");

            repo.DeleteProjectData(id, type);

            ProcessHelper.ProcessAfterDone(data, oper, EventType.Delete, false);
        }

        public ProjectData GetProjectData(int dataid)
        {
            if (dataid == 0)
                throw new Exception("UtilService.UpdateProjectData :: parameter is null");
            IProjectRepository repo = ServiceFactory.CreateInstance<IProjectRepository>();
            return repo.GetProjectData(dataid);
        }
        public ProjectData GetProjectData(int id, ProjectDataType type, FieldName name)
        {
            IProjectRepository repo = ServiceFactory.CreateInstance<IProjectRepository>();
            return repo.GetProjectData(id, type, name);
        }
        public ProjectData GetProjectData(int projectID, int contractID, FieldName name)
        {
            IProjectRepository repo = ServiceFactory.CreateInstance<IProjectRepository>();
            return repo.GetProjectData(projectID, contractID, name);
        }
        public IList<ProjectData> ListProjectData(int id, ProjectDataType type)
        {
            IProjectRepository repo = ServiceFactory.CreateInstance<IProjectRepository>();
            return repo.ListProjectData(id, type);
        }

        public ProjectContract CreateProjectContract(ProjectContract obj, string oper)
        {
            if (obj == null || oper == null)
                throw new Exception("ProjectService.UpdateProjectContract :: parameter is null");

            IProjectRepository repo = ServiceFactory.CreateInstance<IProjectRepository>();
            obj = repo.CreateProjectContract(obj);
            ProcessHelper.ProcessAfterDone(obj, oper, EventType.Create, false);
            return obj;
        }

        public ProjectContract UpdateProjectContract(ProjectContract obj, string oper)
        {
            if (obj == null || oper == null)
                throw new Exception("UtilService.UpdateProjectContract :: parameter is null");

            IProjectRepository repo = ServiceFactory.CreateInstance<IProjectRepository>();

            obj.UpdateDate = DateTime.Now;
            obj.UpdateUser = oper.ToInt();

            repo.UpdateProjectContract(obj);

            ProcessHelper.ProcessAfterDone(obj, oper, EventType.Update, false);

            return obj;
        }

        public ProjectContract GetProjectContract(int contractid)
        {
            if (contractid == 0)
                throw new Exception("ProjectService.GetProjectContract :: parameter is null");
            IProjectRepository repo = ServiceFactory.CreateInstance<IProjectRepository>();
            return repo.GetProjectContract(contractid);
        }

        public ProjectContract GetProjectContract(int projectID, int contractorID)
        {
            if (projectID == 0 || contractorID == 0)
                throw new Exception("ProjectService.GetProjectContract :: parameter is null");

            IProjectRepository repo = ServiceFactory.CreateInstance<IProjectRepository>();
            return repo.GetProjectContract(projectID, contractorID);
        }

        public IList<ProjectContract> ListProjectContract(int projectID, CommonStatus status)
        {
            IProjectRepository repo = ServiceFactory.CreateInstance<IProjectRepository>();
            return repo.ListProjectContract(projectID, status);
        }
        public ModelList<IDictionary<string, string>> ListContractByStatus(int creatorID, CommonStatus status, int start, int limit)
        {
            IProjectRepository repo = ServiceFactory.CreateInstance<IProjectRepository>();
            return repo.ListContractByStatus(creatorID, status, start, limit);
        }
        public ModelList<IDictionary<string, string>> ListContractByStatus(int creatorID, IList<CommonStatus> status, int start, int limit)
        {
            IProjectRepository repo = ServiceFactory.CreateInstance<IProjectRepository>();
            return repo.ListContractByStatus(creatorID, status, start, limit);
        }
        public ModelList<IDictionary<string, string>> ListSponsorContract(int contractorID, IList<CommonStatus> status, int start, int limit)
        {
            IProjectRepository repo = ServiceFactory.CreateInstance<IProjectRepository>();
            return repo.ListSponsorContract(contractorID, status, start, limit);
        }
        public ModelList<IDictionary<string, string>> ListContractByAgent(int agentID, IList<CommonStatus> status, int start, int limit)
        {
            IProjectRepository repo = ServiceFactory.CreateInstance<IProjectRepository>();
            return repo.ListContractByAgent(agentID, status, start, limit);
        }
        public int GetContractNumber(int projectID, CommonStatus status = CommonStatus.All)
        {
            IProjectRepository repo = ServiceFactory.CreateInstance<IProjectRepository>();
            return repo.GetContractNumber(projectID, status);
        }
        public IList<IDictionary<string, string>> ListSponsorMessage()
        {
            IProjectRepository repo = ServiceFactory.CreateInstance<IProjectRepository>();
            return repo.ListSponsorMessage();
        }

        public IList<IDictionary<string, string>> ListAgentSponsorMessage()
        {
            IProjectRepository repo = ServiceFactory.CreateInstance<IProjectRepository>();
            return repo.ListAgentSponsorMessage();
        }

        public void UpdateContractStatus(int id, CommonStatus status, int oper, string remark = "")
        {
            UpdateContractStatus(id, status, "status", oper, remark);
        }

        public void UpdateContractStatusByProject(int projectID, CommonStatus status, int oper, string remark = "")
        {
            IProjectRepository repo = ServiceFactory.CreateInstance<IProjectRepository>();

            var project = Get<Project>(projectID.ToString());
            if (project == null)
                throw new Exception("ProjectService.UpdateContractStatusByProject :: error project id:" + projectID);

            if (project.CreatorID != oper || project.Status != ProjectStatus.Open)
                throw new Exception("ProjectService.UpdateContractStatusByProject :: cannot update contract status under project:" + projectID);

            var lst = repo.ListProjectContract(projectID, CommonStatus.All);

            foreach (var item in lst)
            {
                if (item.Status == CommonStatus.Confirmed || item.Status == CommonStatus.Effective)
                    UpdateContractStatus(item.ContractID, status, "status", oper, "删除所有企业邀请后编辑赞助书");
            }

        }

        public void UpdateContractSubStatus(int id, CommonStatus status, int oper, string remark = "")
        {
            UpdateContractStatus(id, status, "subStatus", oper, remark);
        }

        public void UpdateContractStatus(int id, CommonStatus status, CommonStatus subStatus, int oper, string remark)
        {
            IProjectRepository repo = ServiceFactory.CreateInstance<IProjectRepository>();
            var contract = repo.GetProjectContract(id);
            if (contract == null)
                throw new Exception("ProjectService.UpdateContractStatus :: cannot find contract: " + id);

            CommonStatus oldStatus = contract.Status;
            CommonStatus oldSubStatus = contract.SubStatus;

            contract.UpdateDate = DateTime.Now;
            contract.UpdateUser = oper;
            contract.Status = status;

            if (status != CommonStatus.Deleted)
                contract.SubStatus = subStatus;

            switch (status)
            {
                case CommonStatus.Cancelled:

                    CreateProjectData(contract, FieldName.CancelRemark, remark, oper);
                    CreateProjectData(contract, FieldName.ContractStep1Date, DateTime.Now.ToString(DataFormatter.LongDate), oper);
                    break;
            }

            UpdateProjectContract(contract, oper.ToString());

            CreateLifecycleEvent(contract, oldStatus.ToString(), status.ToString(), oper, LifeCycleFun.ContractStatusChanged, remark);

            if (status != CommonStatus.Deleted)
                CreateLifecycleEvent(contract, oldSubStatus.ToString(), subStatus.ToString(), oper, LifeCycleFun.ContractSubStatusChanged, remark);
        }

        public void CreateProjectCollection(ProjectCollection obj, string oper)
        {
            IProjectRepository repo = ServiceFactory.CreateInstance<IProjectRepository>();
            repo.CreateProjectCollection(obj);

            ProcessHelper.ProcessAfterDone(obj, oper, EventType.Create, false);
        }

        public ProjectCollection GetProjectCollection(int userID, int projectID)
        {
            IProjectRepository repo = ServiceFactory.CreateInstance<IProjectRepository>();
            return repo.GetProjectCollection(userID, projectID);
        }

        public void DeleteProjectCollection(int collectionID, string oper)
        {
            IProjectRepository repo = ServiceFactory.CreateInstance<IProjectRepository>();

            var obj = repo.GetProjectCollection(collectionID);
            if (obj == null)
                throw new Exception("ProjectService.DeleteProjectCollection :: parameter is null");

            repo.DeleteProjectCollection(collectionID);

            ProcessHelper.ProcessAfterDelete(collectionID.ToString(), obj, oper, EventType.Delete, false);
        }
        public IList<ProjectCollection> ListProjectCollection(int userID)
        {
            IProjectRepository repo = ServiceFactory.CreateInstance<IProjectRepository>();
            return repo.ListProjectCollection(userID);
        }
        public ModelList<IDictionary<string, string>> ListProjectCollection(int userID, int start, int limit)
        {
            IProjectRepository repo = ServiceFactory.CreateInstance<IProjectRepository>();
            return repo.ListProjectCollection(userID, start, limit);
        }

        public int CountProjectCollection(int projectID)
        {
            IProjectRepository repo = ServiceFactory.CreateInstance<IProjectRepository>();
            return repo.CountProjectCollection(projectID);
        }

        public ModelList<Project> Search(IDictionary<SearchKey, string> dicCondition, int start, int limit)
        {
            IProjectRepository repo = ServiceFactory.CreateInstance<IProjectRepository>();
            return repo.Search(dicCondition, start, limit);
        }

        public ModelList<Project> ListProjectByBelongID(int belongID, int start, int limit)
        {
            IProjectRepository repo = ServiceFactory.CreateInstance<IProjectRepository>();
            return repo.ListProjectByBelongID(belongID, start, limit);
        }

        public int CountProjectCreatedPerDay(int userID)
        {
            IProjectRepository repo = ServiceFactory.CreateInstance<IProjectRepository>();
            return repo.CountProjectCreatedPerDay(userID);
        }

        public ProjectSearch CreateProjectSearch(ProjectSearch obj, string oper)
        {
            IProjectRepository repo = ServiceFactory.CreateInstance<IProjectRepository>();

            obj = repo.CreateProjectSearch(obj);
            ProcessHelper.ProcessAfterDone(obj, oper, EventType.Create, false);
            return obj;
        }

        public void DeleteProjectSearch(string code)
        {
            IProjectRepository repo = ServiceFactory.CreateInstance<IProjectRepository>();
            repo.DeleteProjectSearch(code);
        }

        private void CreateProjectData(ProjectContract contract, FieldName name, string value, int oper)
        {
            var data = GetProjectData(contract.ContractID, ProjectDataType.Contract, name);
            if (data == null)
            {
                data = new ProjectData();
                data.ContractID = contract.ContractID;
                data.ProjectID = contract.ProjectID;
                data.DataName = name;
                data.DataType = ProjectDataType.Contract;
                data.DataValue = value;
                data.UpdateDate = DateTime.Now;
                data.UpdateUser = oper;

                CreateProjectData(data, oper.ToString());
            }
            else
            {
                data.DataValue = value;
                data.UpdateDate = DateTime.Now;
                data.UpdateUser = oper;

                UpdateProjectData(data, oper.ToString());
            }
        }

        private void UpdateContractStatus(int id, CommonStatus status, string type, int oper, string remark)
        {
            IProjectRepository repo = ServiceFactory.CreateInstance<IProjectRepository>();
            var contract = repo.GetProjectContract(id);
            if (contract == null)
                throw new Exception("ProjectService.UpdateContractStatus :: cannot find contract: " + id);

            bool isSub = type == "status" ? false : true;
            CommonStatus oldStatus = isSub ? contract.SubStatus : contract.Status;

            if (isSub)
                contract.SubStatus = status;
            else
                contract.Status = status;

            contract.UpdateDate = DateTime.Now;
            contract.UpdateUser = oper;

            switch (status)
            {
                case CommonStatus.Effective:

                    var template = ContractTemplateUtil.CreateInstance();
                    var value = template.GetTemplateValue(contract);

                    CreateProjectData(contract, FieldName.ContractContent, value[FieldName.ContractContent], oper);
                    CreateProjectData(contract, FieldName.PercentageMoney, value[FieldName.PercentageMoney], oper);
                    CreateProjectData(contract, FieldName.ContractStep1Date, DateTime.Now.ToString(DataFormatter.LongDate), oper);

                    contract.TemplateVersion = template.GetCurrentVersion();

                    Random don = new Random();

                    contract.ContractCode = "BSC" + DateTime.Now.ToString("yyMMddHHmmss") + don.Next(100, 1000);
                    contract.SignDate = DateTime.Now;

                    MessageUtil.SendMessage(status, oper, 0, contract);

                    break;

                case CommonStatus.FeedbackRejected:

                    CreateProjectData(contract, FieldName.RejectRemark, remark, oper);
                    CreateProjectData(contract, FieldName.ContractStep4Date, DateTime.Now.ToString(DataFormatter.LongDate), oper);
                    MessageUtil.SendMessage(status, oper, 0, contract);
                    break;
                case CommonStatus.FeedbackApproved:
                case CommonStatus.FeedbackSubmitted:
                    CreateProjectData(contract, FieldName.ContractStep4Date, DateTime.Now.ToString(DataFormatter.LongDate), oper);
                    MessageUtil.SendMessage(status, oper, 0, contract);
                    break;
            }

            UpdateProjectContract(contract, oper.ToString());

            LifecycleEvent lcEvent = new LifecycleEvent();
            lcEvent.EventID = contract.ContractID;
            lcEvent.ParentID = contract.ProjectID;
            lcEvent.ValueFrom = oldStatus.ToString();
            lcEvent.ValueTo = isSub ? contract.SubStatus.ToString() : contract.Status.ToString();
            lcEvent.UpdatedTime = DateTime.Now;
            lcEvent.UpdatedUser = oper;
            lcEvent.Fun = isSub ? LifeCycleFun.ContractSubStatusChanged : LifeCycleFun.ContractStatusChanged;
            lcEvent.Remark = remark;

            UtilService service = ServiceFactory.CreateInstance<UtilService>();
            service.CreateLifecycleEvent(lcEvent, oper.ToString());
        }

        private void CreateLifecycleEvent(ProjectContract contract, string from, string to, int oper, LifeCycleFun fun, string remark)
        {
            LifecycleEvent lcEvent = new LifecycleEvent();
            lcEvent.EventID = contract.ContractID;
            lcEvent.ParentID = contract.ProjectID;
            lcEvent.ValueFrom = from;
            lcEvent.ValueTo = to;
            lcEvent.UpdatedTime = DateTime.Now;
            lcEvent.UpdatedUser = oper;
            lcEvent.Fun = fun;
            lcEvent.Remark = remark;

            UtilService service = ServiceFactory.CreateInstance<UtilService>();
            service.CreateLifecycleEvent(lcEvent, oper.ToString());
        }
    }
}
